"""
Author: Jian SuiYue kaohx0214@yeah.net
Date: 2025-04-22 23:59:36
LastEditTime: 2025-05-23 18:01:24
FilePath: LibraryManagerStudio/datamodel/db.py
"""

import datetime as dt
import uuid
from enum import Enum
from typing import Optional

from pydantic import field_serializer
from sqlalchemy import Column, TEXT
from sqlmodel import SQLModel, Field, func, DateTime


class FriendStatus(str, Enum):
    ACCEPTED = '0'  # 已接受
    PENDING = '1'  # 待接受
    REJECTED = '2'  # 已拒绝
    BLOCKED = '3'  # 拉黑中


class BookStatus(str, Enum):
    PUBLISH = '0'  # 发布
    PENDING = '1'  # 待审核
    REJECTED = '2'  # 下架


class BorrowStatus(str, Enum):
    BORROWING = '0'  # 借阅中
    RETURNED = '1'  # 已归还
    OVERDUE = '2'  # 逾期


class LogStatus(str, Enum):
    SUCCESSFUL = '0'
    WARNING = '1'
    ERROR = '2'


class UserRole(str, Enum):
    ADMIN = '0'
    USER = '1'


class User(SQLModel, table=True):
    __table_args__ = {"sqlite_autoincrement": True}
    id: int = Field(default=None, primary_key=True)
    wechat_id: str = Field(unique=True)
    username: str = Field(nullable=False)
    password: Optional[str] = Field(default=None, nullable=True)
    cover: Optional[str] = Field(default=None, sa_column=Column(TEXT))
    description: Optional[str] = Field(default=None, nullable=True)
    is_admin: bool = Field(default=False, nullable=False)
    created_at: dt.datetime = Field(  # first upload time
        default_factory=dt.datetime.now,
        sa_column=Column(DateTime(timezone=True), server_default=func.now())
    )
    updated_at: dt.datetime = Field(  # last updated time
        default_factory=dt.datetime.now,
        sa_column=Column(DateTime(timezone=True), onupdate=func.now()),
    )

    @field_serializer('created_at', 'updated_at')
    def serialize_dt(self, value):
        if isinstance(value, str):
            return dt.datetime.fromisoformat(value)
        return value


class Friend(SQLModel, table=True):
    __table_args__ = {"sqlite_autoincrement": True}  # primary key use true autoincrement
    id: int = Field(default=None, primary_key=True)
    uid: int = Field(foreign_key="user.id")  # your uid
    friend_uid: int = Field(foreign_key="user.id")  # friend uid
    status: FriendStatus = Field(default=FriendStatus.ACCEPTED, nullable=False)
    created_at: dt.datetime = Field(  # first upload time
        default_factory=dt.datetime.now,
        sa_column=Column(DateTime(timezone=True), server_default=func.now())
    )
    updated_at: dt.datetime = Field(  # last updated time
        default_factory=dt.datetime.now,
        sa_column=Column(DateTime(timezone=True), onupdate=func.now()),
    )

    @field_serializer('created_at', 'updated_at')
    def serialize_dt(self, value):
        if isinstance(value, str):
            return dt.datetime.fromisoformat(value)
        return value


class Book(SQLModel, table=True):
    __table_args__ = {"sqlite_autoincrement": True}
    id: int = Field(default=None, primary_key=True)
    uid: int = Field(foreign_key="user.id")
    cover: Optional[str] = Field(default=None, sa_column=Column(TEXT))
    isbn: Optional[str] = Field(index=True, max_length=11, unique=True)
    title: str = Field(index=True, nullable=False)
    author: str = Field(index=True, nullable=False)
    description: Optional[str] = Field(default=None, nullable=True)
    introduction: str = Field(default='上传者很懒，还没有填写简介哦~。', nullable=False)
    borrow_id: Optional[int] = Field(default=None, nullable=True)  # borrow id
    category_id: Optional[int] = Field(default=None, nullable=True)  # category id 
    status: BookStatus = Field(default=BookStatus.PENDING, nullable=False)
    created_at: dt.datetime = Field(  # first upload time
        default_factory=dt.datetime.now,
        sa_column=Column(DateTime(timezone=True), server_default=func.now())
    )
    updated_at: dt.datetime = Field(  # last updated time
        default_factory=dt.datetime.now,
        sa_column=Column(DateTime(timezone=True), onupdate=func.now()),
    )

    @field_serializer('created_at', 'updated_at')
    def serialize_dt(self, value):
        if isinstance(value, str):
            return dt.datetime.fromisoformat(value)
        return value


class Borrow(SQLModel, table=True):
    __table_args__ = {"sqlite_autoincrement": True}
    id: int = Field(default=None, primary_key=True)
    user_id: int = Field(foreign_key="user.id")
    created_at: dt.datetime = Field(  # first upload time
        default_factory=dt.datetime.now,
        sa_column=Column(DateTime(timezone=True), server_default=func.now())
    )
    updated_at: dt.datetime = Field(  # last updated time
        default_factory=dt.datetime.now,
        sa_column=Column(DateTime(timezone=True), onupdate=func.now()),
    )
    actual_return_date: Optional[dt.datetime] = Field(
        default=None,
        sa_column=Column(DateTime(timezone=True), nullable=True)
    )
    expected_return_date: dt.datetime = Field(
        default=None,
        sa_column=Column(DateTime(timezone=True), nullable=False)
    )
    status: BorrowStatus = Field(
        default=BorrowStatus.BORROWING,
        nullable=False
    )

    @field_serializer('created_at', 'updated_at', 'actual_return_date', 'expected_return_date')
    def serialize_dt(self, value):
        if isinstance(value, str):
            return dt.datetime.fromisoformat(value)
        return value


class Category(SQLModel, table=True):
    __table_args__ = {"sqlite_autoincrement": True}
    id: int = Field(default=None, primary_key=True)
    name: str = Field(unique=True, nullable=False)  # 类型名字不重复
    description: Optional[str] = Field(default=None)
    created_at: dt.datetime = Field(  # first upload time
        default_factory=dt.datetime.now,
        sa_column=Column(DateTime(timezone=True), server_default=func.now())
    )
    updated_at: dt.datetime = Field(  # last updated time
        default_factory=dt.datetime.now,
        sa_column=Column(DateTime(timezone=True), onupdate=func.now()),
    )

    @field_serializer('created_at', 'updated_at')
    def serialize_dt(self, value):
        if isinstance(value, str):
            return dt.datetime.fromisoformat(value)
        return value


class Session(SQLModel, table=True):
    __table_args__ = {"sqlite_autoincrement": True}
    id: int = Field(default=None, primary_key=True)
    user_id: int = Field(foreign_key="user.id")
    created_at: dt.datetime = Field(  # first upload time
        default_factory=dt.datetime.now,
        sa_column=Column(DateTime(timezone=True), server_default=func.now())
    )
    updated_at: dt.datetime = Field(  # last updated time
        default_factory=dt.datetime.now,
        sa_column=Column(DateTime(timezone=True), onupdate=func.now()),
    )

    @field_serializer('created_at', 'updated_at')
    def serialize_dt(self, value):
        if isinstance(value, str):
            return dt.datetime.fromisoformat(value)
        return value


class Message(SQLModel, table=True):
    __table_args__ = {"sqlite_autoincrement": True}
    id: int = Field(default=None, primary_key=True)
    session_id: int = Field(foreign_key="session.id")
    message: str = Field(nullable=False)
    created_at: dt.datetime = Field(  # first upload time
        default_factory=dt.datetime.now,
        sa_column=Column(DateTime(timezone=True), server_default=func.now())
    )
    updated_at: dt.datetime = Field(  # last updated time
        default_factory=dt.datetime.now,
        sa_column=Column(DateTime(timezone=True), onupdate=func.now()),
    )

    @field_serializer('created_at', 'updated_at')
    def serialize_dt(self, value):
        if isinstance(value, str):
            return dt.datetime.fromisoformat(value)
        return value


# 这只是像我这个小型项目为了使用token而在sqlite创建表格，大型项目应该在redis

class Token(SQLModel, table=True):
    __table_args__ = {"sqlite_autoincrement": True}
    id: int | None = Field(default=None, primary_key=True)  # SQLite 会自动填充
    jti: str = Field(default_factory=lambda: str(uuid.uuid4()))  # 每次插入时生成新 UUID
    user_id: int = Field(foreign_key="user.id", index=True)
    token: str  # 必须提供 token，不能为 NULL
    expires_at: dt.datetime = Field(
        sa_column=Column(DateTime(timezone=True), nullable=False)
    )
    created_at: dt.datetime = Field(
        default_factory=dt.datetime.now,
        sa_column=Column(DateTime(timezone=True), server_default=func.now())
    )
    updated_at: dt.datetime = Field(  # last updated time
        default_factory=dt.datetime.now,
        sa_column=Column(DateTime(timezone=True), onupdate=func.now()),
    )

    @field_serializer('expires_at', 'created_at', 'updated_at')
    def serialize_dt(self, value):
        if isinstance(value, str):
            return dt.datetime.fromisoformat(value)
        return value
